package com.wushijia.test.java7;

import com.wushijia.model.User;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;

import lombok.extern.slf4j.Slf4j;

/**
 * https://blog.csdn.net/s10461/article/details/53941091
 *
 * @author pc
 */
@Slf4j
public class GenericDemo {

  public static void showKeyValue(Generic<Number> obj) {
    log.info("泛型测试,key value is {}", obj.getKey());
  }

  //解决具体类型不确定
  public static void showKeyValue1(Generic<?> obj) {
    log.info("泛型之通配符测试,key value is {}", obj.getKey());
  }

  public static void main(String[] args) {
    //jdk7之前的写法
    Map<String, Map<String, Map<Integer, List<User>>>> stringMapMap1 = new Hashtable<String, Map<String, Map<Integer, List<User>>>>();
    //jdk7之后泛型实例化简写
    Map<String, Map<String, Map<Integer, List<User>>>> stringMapMap2 = new Hashtable<>();

    //运行期报错，应该使用泛型，以便在编译器校验
//    List arrayList = new ArrayList();
//    arrayList.add("aaaa");
//    arrayList.add(100);
//
//    for (int i = 0; i < arrayList.size(); i++) {
//      String item = (String) arrayList.get(i);
//      log.info("泛型测试,item = {}", item);
//    }

    //在运行期已无泛型概念，只在编译器有效
    List<String> stringArrayList = new ArrayList<String>();
    List<Integer> integerArrayList = new ArrayList<Integer>();
    Class classStringArrayList = stringArrayList.getClass();
    Class classIntegerArrayList = integerArrayList.getClass();
    if (classStringArrayList.equals(classIntegerArrayList)) {
      log.info("泛型测试,类型相同");
    }

    //泛型类（集合类），泛型接口(集合接口)，泛型方法
    //不能对确切的泛型类型使用instanceof操作
    Generic<Integer> generic = new Generic<>(100);
    //if(generic instanceof Generic<Number>){}

    Generic<Integer> gInteger = new Generic<Integer>(123);
    Generic<Number> gNumber = new Generic<Number>(456);

    showKeyValue(gNumber);
    //同一种泛型可以对应多个版本（因为参数类型是不确定的），不同版本的泛型类实例是不兼容的
    //showKeyValue(gInteger);
    showKeyValue1(gInteger);

    //只能使用通配符创建数组，在编译时会忽略泛型，所以如果不能在编译器确定类型，否则会出现类型转换异常
    List<?>[] ListArr = new ArrayList<?>[10];
    //List<String>[] lsa = new List<String>[10];

  }

  static class Generic<T> {

    //key这个成员变量的类型为T,T的类型由外部指定
    private T key;

    public Generic(T key) { //泛型构造方法形参key的类型也为T，T的类型由外部指定
      this.key = key;
    }

    public T getKey() { //泛型方法getKey的返回值类型为T，T的类型由外部指定
      return key;
    }
  }
}

